﻿using AutoMapper;
using FreeSql;
using Kalman;
using Kalman.Jwt;
using Kalman.Security;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace QuDao.Api
{
    public static class Extensions
    {
        #region FreeSql数据库配置
        public static void ConfigureDatabase(this IServiceCollection services)
        {
            var dbType = DataType.MySql;
            var css = AppConfig.Instance.GetConnectionStringSettings();
            //switch (css.ProviderName)
            //{
            //    case "MySql.Data.MySqlClient":
            //        dbType = DataType.MySql;
            //        break;
            //    default:
            //        break;
            //}

            var sqlBuilder = new FreeSqlBuilder()
                    .UseConnectionString(dbType, css.ConnectionString)
                    .UseAutoSyncStructure(false)
                    .UseLazyLoading(false)
                    .UseNoneCommandParameter(true);//不使用命令参数化执行，针对 Insert/Update，也可临时使用 IInsert/IUpdate.NoneParameter()


            //监听所有命令
            sqlBuilder.UseMonitorCommand(cmd => { }, (cmd, traceLog) =>
            {
                //Console.WriteLine($"{cmd.CommandText}\n{traceLog}\r\n");
                Console.WriteLine($"{cmd.CommandText}\r\n");
            });

            var freeSql = sqlBuilder.Build();
            services.AddSingleton(freeSql);

            //监听Curd操作
            //freeSql.Aop.CurdBefore += (s, e) =>
            //{
            //    Console.WriteLine($"{e.Sql}\r\n");
            //};
        }
        #endregion

        #region Swagger配置，参考：https://www.cnblogs.com/shanfeng1000/p/13476831.html
        public static IServiceCollection ConfigureSwagger(this IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("qudao", new OpenApiInfo { Title = "渠道通平台API", Version = "v1" });

                // Set the comments path for the Swagger JSON and UI.
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath, true); //第二个参数为true表示包含控制器注释
                c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "QuDao.Common.xml"));
                //c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Kalman.xml"));

                c.SwaggerGeneratorOptions.IgnoreObsoleteActions = true;//忽略标记[Obsolete]的接口
                //c.OperationFilter<AddSwaggerParameter>();//加入自定义参数

                //定义JwtBearer认证方式一
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                {
                    Description = "直接在输入框中输入认证信息，不需要在开头添加Bearer",
                    Name = "Authorization",//jwt默认的参数名称
                    In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                    Type = SecuritySchemeType.Http,
                    Scheme = "bearer"
                });

                //定义JwtBearer认证方式二
                //c.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
                //{
                //    Description = "直接在下框中输入Bearer {token}（注意：两者之间是一个空格）",
                //    Name = "Authorization",//jwt默认的参数名称
                //    In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                //    Type = SecuritySchemeType.ApiKey
                //});

                //声明一个Scheme，注意下面的Id要和上面AddSecurityDefinition中的参数name一致
                var scheme = new OpenApiSecurityScheme()
                {
                    Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
                };
                //注册全局认证（所有的接口都可以使用认证）
                c.AddSecurityRequirement(new OpenApiSecurityRequirement()
                {
                    [scheme] = Array.Empty<string>()
                });
            });

            return services;
        }

        public static void ConfigureSwagger(this IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/qudao/swagger.json", "QuDaoAPI v1");
            });
        }
        #endregion

        public static void ConfigureCors(this IServiceCollection services)
        {
            //services.AddCors(options =>  //跨域设置
            //{
            //    options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin()
            //        .AllowAnyMethod()
            //        .AllowAnyHeader()
            //        .AllowCredentials());
            //});

            services.AddCors(options =>  //跨域设置
            {
                options.AddPolicy("CorsPolicy", builder =>
                    builder.AllowAnyMethod()
                    .WithOrigins("https://api-ac.banan8.com", "https://api-ac.meijinglianlian.com", "http://api-ac.meijinglianlian.com")
                    //.AllowAnyOrigin()
                    .SetIsOriginAllowed(_ => true)
                    .AllowAnyHeader()
                    .AllowCredentials());
            });
        }

        /// <summary>
        /// 配置AutoMapper对象映射关系
        /// </summary>
        public static IServiceCollection ConfigureAutoMapper(this IServiceCollection services)
        {
            //services.AddAutoMapper(typeof(Startup));

            //如果不想使用 AddAutoMapper()  通过反射自动找出 Profile ，建议使用这种方式
            AutoMapper.IConfigurationProvider config = new MapperConfiguration(cfg =>
            {
                cfg.AddProfile<MappingProfile>();
            });
            services.AddSingleton(config);
            services.AddScoped<IMapper, Mapper>();

            return services;
        }

        public static bool IsDevelopment(this IHostEnvironment env) => "Development".Equals(env.EnvironmentName);
        public static bool IsTesting(this IHostEnvironment env) => "Testing".Equals(env.EnvironmentName);
        public static bool IsProduction(this IHostEnvironment env) => "Production".Equals(env.EnvironmentName);
        public static bool IsStaging(this IHostEnvironment env) => "Staging".Equals(env.EnvironmentName);


        #region HttpRequest Extensions

        /// <summary>
        /// 获取当前请求的Body内容字符串（支持多次读取）
        /// </summary>
        public static string GetBodyString(this HttpRequest request)
        {
            request.Body.Seek(0, SeekOrigin.Begin);

            using var buffer = new MemoryStream();
            request.Body.CopyToAsync(buffer);
            buffer.Position = 0L;//重置内存流数据的起始位置

            using var reader = new StreamReader(buffer, Encoding.UTF8);
            var body = reader.ReadToEnd();
            request.Body.Seek(0, SeekOrigin.Begin);//这里Body数据流要复位，否则会导致Body参数绑定失败
            return body;
        }


        #endregion

        #region Api接口认证
        /// <summary>
        /// JWT令牌认证
        /// </summary>
        public static IActionResult JwtAuth(this AuthorizationFilterContext context)
        {
            IActionResult result = null;
            var auth = context.HttpContext.Request.Headers["Authorization"];
            if (auth.Count > 0)
            {
                var jwt = ServiceLocator.Instance.GetRequiredService<JwtBuilder>();
                var token = auth[0].Replace("Bearer ", string.Empty);
                var ex = jwt.Check(token);
                if (ex != null)
                {
                    result = new UnauthorizedObjectResult(new { code = ex.ErrorCode, msg = ex.Message });
                }
            }
            else
            {
                result = new UnauthorizedObjectResult(new { code = "401", msg = "无效的请求" });
            }

            return result;
        }

        /// <summary>
        /// 数字签名认证
        /// </summary>
        public static IActionResult SignAuth(this AuthorizationFilterContext context)
        {
            IActionResult result = null;
            var request = context.HttpContext.Request;

            //var body = request.GetBodyString();

            var ts = string.Empty;
            var nonce = string.Empty;
            var sign = string.Empty;
            var dic = new Dictionary<string, string>();
            foreach (var item in request.Query)
            {
                if (item.Key == "sign") { sign = item.Value; continue; }
                dic.Add(item.Key, item.Value);
            }

            if (dic.ContainsKey("ts")) ts = dic["ts"];
            if (dic.ContainsKey("nonce")) nonce = dic["nonce"];

            if (string.IsNullOrEmpty(nonce))
            {
                result = new BadRequestObjectResult(new { code = 400, msg = "nonce参数值不能为空" });
                return result;
            }
            ApiUtils.Instance.CheckNonce(nonce);

            var timestamp = ConvertUtil.ToInt64(ts, 0);
            if (timestamp == 0)
            {
                result = new BadRequestObjectResult(new { code = 400, msg = "ts参数值无效" });
                return result;
            }

            var time = TimeStampUtil.GetFromUnixTimeStamp(timestamp);
            if (time.AddMinutes(15) < DateTime.Now)
            {
                result = new BadRequestObjectResult(new { code = 400, msg = "请求已过期" });
                return result;
            }

            var settings = AppConfig.Instance.GetAppSettings<AppSettings>();
            var compareSign = ApiUtils.Instance.GetSign(dic, settings.SecretKey);
            if (compareSign != sign)
            {
                result = new BadRequestObjectResult(new { code = 400, msg = "无效的签名" });
                return result;
            }

            return result;
        }

        /// <summary>
        /// IP认证（白名单，黑名单）
        /// </summary>
        public static IActionResult IpAuth(this AuthorizationFilterContext context)
        {
            IActionResult result = null;
            var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
            var settings = AppConfig.Instance.GetAppSettings<AppSettings>();
            var ipWhiteList = settings.IPWhiteList.Split(',');// new string[] { "::1", "127.0.0.1", "192.168.0.1" };

            var bytes = remoteIp.GetAddressBytes();
            var badIp = true;
            foreach (var address in ipWhiteList)
            {
                var testIp = IPAddress.Parse(address);
                if (testIp.GetAddressBytes().SequenceEqual(bytes))
                {
                    badIp = false;
                    break;
                }
            }

            if (badIp)
            {
                context.Result = new UnauthorizedObjectResult(new { code = "401", msg = "无效的请求" });
            }

            return result;
        }

        #endregion
    }


}
